package com.tabbinder.client;

import java.util.ArrayList;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Bottom part of the right panel containing the links of a binder
 * 
 * @author Tatiana Kichkaylo
 */
public class LinksPanel {
	private ListItem selectedItem = null;
	private MasterBind master;

	private VerticalPanel linkList;
	private Label addButton;
	private Label deleteButton;
	private ArrayList<ItemPanel> boxes = new ArrayList<ItemPanel>();

	public LinksPanel(MasterBind master) {
		this.master = master;

		linkList = new VerticalPanel();
		RootPanel.get("linkList").add(linkList);

		RootPanel buttons = RootPanel.get("linkButtons");
		addButton = new Label("Add link");
		addButton.addStyleName("binderButton");
		addButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				if (addButton.getStyleName().contains("disabled"))
					return;
				AddDialog dia = new AddDialog();
				dia.center();
			}
		});
		buttons.add(addButton);
		deleteButton = new Label("Delete selected links");
		deleteButton.addStyleName("binderButton");
		deleteButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				if (deleteButton.getStyleName().contains("disabled"))
					return;
				doDeleteLinks();
			}
		});
		buttons.add(deleteButton);

		selectItem(null);
	}

	private void createElement(JSONObject element) {
		ItemPanel box = new ItemPanel(element);
		linkList.add(box);
		boxes.add(box);
	}

	class AddDialog extends DialogBox {
		AddDialog() {
			setText("Add link");

			VerticalPanel vpanel = new VerticalPanel();

			vpanel.add(new Label("URL"));
			final TextBox url = new TextBox();
			url.addStyleName("addLinkText");
			vpanel.add(url);

			vpanel.add(new Label("Description"));
			final TextBox title = new TextBox();
			title.addStyleName("addLinkText");
			vpanel.add(title);

			HorizontalPanel hpanel = new HorizontalPanel();
			vpanel.add(hpanel);
			Button ok = new Button("OK");
			ok.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					AddDialog.this.hide();
					String link = url.getText();
					String desc = title.getText();
					if ("".equals(desc))
						desc = null;
					if (link.length() > 0) {
						JSONObject el = appendElement(link, desc);
						createElement(el);
					}
				}
			});
			hpanel.add(ok);
			Button cancel = new Button("Cancel");
			cancel.addClickHandler(new ClickHandler() {
				public void onClick(ClickEvent event) {
					AddDialog.this.hide();
				}
			});
			hpanel.add(cancel);
			setWidget(vpanel);
		}
	}

	public void selectItem(ListItem item) {
		selectedItem = item;
		linkList.clear();
		boxes.clear();

		if (item == null) {
			addButton.addStyleName("disabled");
			deleteButton.addStyleName("disabled");
			return;
		}
		addButton.removeStyleName("disabled");
		deleteButton.removeStyleName("disabled");

		JSONArray array = (JSONArray) item.getJson().get("links");
		if (array != null)
			for (int i = 0; i < array.size(); i++) {
				JSONObject link = (JSONObject) array.get(i);
				if (link != null) {
					createElement(link);
				}
			}
	}

	/** Add new URL to the list on the server */
	private JSONObject appendElement(String url, String title) {
		// Paranoia
		if (selectedItem == null)
			return null;
		JSONArray array = (JSONArray) selectedItem.getJson().get("links");
		if (array == null) {
			array = new JSONArray();
			selectedItem.getJson().put("links", array);
		}
		JSONObject obj = new JSONObject();
		obj.put("url", new JSONString(url));
		if (title != null)
			obj.put("title", new JSONString(title));
		array.set(array.size(), obj);
		master.submitUpdate(selectedItem);
		return obj;
	}

	protected void doDeleteLinks() {
		// Paranoia
		if (selectedItem == null)
			return;
		JSONArray array = (JSONArray) selectedItem.getJson().get("links");
		if (array == null)
			return;

		for (ItemPanel box : boxes)
			if (box.isSelected()) {
				// Find the corresponding element
				for (int i = 0; i < array.size(); i++) {
					JSONObject url = (JSONObject) array.get(i);
					if (url == null)
						continue;
					if (url.equals(box.element)) {
						array.set(i, null);
						break;
					}
				}
			}
		master.submitUpdate(selectedItem);
		selectItem(selectedItem);
	}

	class ItemPanel extends VerticalPanel implements BlurHandler, ClickHandler,
			KeyPressHandler, MouseDownHandler {
		private CheckBox box;
		private TextBox descrEdit;
		private Label descrText;
		protected JSONObject element;

		public ItemPanel(JSONObject element) {
			this.element = element;
			JSONString v1 = (JSONString) element.get("url");
			String url = (v1 == null) ? null : v1.stringValue();
			v1 = (JSONString) element.get("title");

			this.box = new CheckBox(url);
			box.setTitle(url);
			descrEdit = new TextBox();
			descrText = new Label();
			if (v1 != null)
				descrText.setText(v1.stringValue());
			descrText.addClickHandler(this);
			descrEdit.addBlurHandler(this);
			descrEdit.addKeyPressHandler(this);
			box.addClickHandler(this);
			descrEdit.addStyleName("listItemShifted");
			descrText.addStyleName("listItemShifted");
			this.add(box);
			this.add(descrText);
		}

		public String getDescr() {
			return descrText.getText();
		}

		public boolean isSelected() {
			return box.getValue();
		}

		private void backFromEdit(boolean save) {
			String nv = descrEdit.getText();
			if (save && !descrText.getText().equals(nv)) {
				descrText.setText(nv);
				element.put("title", new JSONString(nv));
				// Assuming out element is part of selectedItem
				master.submitUpdate(selectedItem);
			}
			this.remove(descrEdit);
			this.add(descrText);
		}

		public void onBlur(BlurEvent event) {
			backFromEdit(true);
		}

		public void onKeyPress(KeyPressEvent event) {
			switch (event.getCharCode()) {
			case 27:
				backFromEdit(false);
				break;
			case 13:
				backFromEdit(true);
				break;
			}
		}

		public void onClick(ClickEvent event) {
			descrEdit.setText(descrText.getText());
			this.remove(descrText);
			this.add(descrEdit);
		}

		public void onMouseDown(MouseDownEvent event) {
			if (event.isAltKeyDown()) {
				onClick(null);
			}
		}
	}
}
